package org.github.manx98.jlibhac.tools.fssystem.ncautils;

import org.github.manx98.jlibhac.common.math.IByteUtil;
import org.github.manx98.jlibhac.common.math.Uint64;
import org.github.manx98.jlibhac.fssystem.*;

import static org.github.manx98.jlibhac.tools.fssystem.ncautils.NcaHeader.SectionCount;

/**
 * @author Manx98
 * @version 1.0
 * @since 2022/10/3 16:56
 */
public class NcaFsHeader {
    private final byte[] header;
    NcaCompressionInfo compressionInfo = new NcaCompressionInfo();
    FsHeaderStruct headerStruct = new FsHeaderStruct();

    public NcaFsHeader(byte[] headerData) {
        this.header = headerData;
        IByteUtil.mapToStruct(this.headerStruct, headerData, 0);
        IByteUtil.mapToStruct(this.compressionInfo, headerData,FsHeaderStruct.CompressionInfoOffset, FsHeaderStruct.CompressionInfoSize);
    }

    public boolean isPatchSection() {
        return getPatchInfo().patchInfoStruct.RelocationTreeSize != 0;
    }

    public NcaFsPatchInfo getPatchInfo() {
        return new NcaFsPatchInfo(IByteUtil.slice(header, FsHeaderStruct.PatchInfoOffset, FsHeaderStruct.PatchInfoSize));
    }

    public boolean existsSparseLayer() {
        return getSparseInfo().Generation.intValue() != 0;
    }

    public NcaSparseInfo getSparseInfo() {
        NcaSparseInfo ncaSparseInfo = new NcaSparseInfo();
        IByteUtil.mapToStruct(ncaSparseInfo, header, FsHeaderStruct.SparseInfoOffset, FsHeaderStruct.SparseInfoSize);
        return ncaSparseInfo;
    }

    public NcaEncryptionType getEncryptionType() {
        return headerStruct.EncryptionType;
    }

    private void validateSectionIndex(int index) {
        if (index < 0 || index >= SectionCount) {
            throw new IllegalArgumentException("NCA section index must be between 0 and 3. Actual: " + index);
        }
    }

    public Uint64 getCounter() {
        return headerStruct.UpperCounter;
    }

    public NcaHashType getHashType() {
        return headerStruct.HashType;
    }

    public NcaFsIntegrityInfoSha256 getIntegrityInfoSha256() {
        return new NcaFsIntegrityInfoSha256(IByteUtil.slice(header, FsHeaderStruct.IntegrityInfoOffset, FsHeaderStruct.IntegrityInfoSize));
    }

    public NcaFsIntegrityInfoIvfc getIntegrityInfoIvfc() {
        return new NcaFsIntegrityInfoIvfc(IByteUtil.slice(header, FsHeaderStruct.IntegrityInfoOffset, FsHeaderStruct.IntegrityInfoSize));
    }

    public boolean existsCompressionLayer() {
        return getCompressionInfo().MetaOffset != 0 && getCompressionInfo().MetaSize != 0;
    }

    NcaCompressionInfo getCompressionInfo() {
        return compressionInfo;
    }

    public NcaFormatType getFormatType() {
        return headerStruct.FormatType;
    }
}
